package com.tegistuff.webos.run.debugger.commands;

import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.tegistuff.webos.run.debugger.WebOSExecutionStack;
import com.tegistuff.webos.run.debugger.WebOSStackFrame;
import com.tegistuff.webos.run.debugger.WebOSSuspendContext;
import com.tegistuff.webos.run.debugger.breakpoints.WebOSBreakpointWrapper;
import com.tegistuff.webos.run.debugger.infrastructure.WebOSThreadHelper;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * WebOSBuildExecutionStackCommand.java
 *
 * This command is a meta command to build the necessary structure to provide
 * IDEA with a V8 stack trace. It invokes a trace command and processes its
 * response in a background thread.
 *
 * Copyright (C) 2011-2012 Timo Tegtmeier.
 * All rights reserved.
 */
public class WebOSBuildExecutionStackCommand extends BaseWebOSCommand {

    private WebOSGetStackTraceCommand myTraceCommand;
    private JSONObject myStackTrace;
    private boolean myCausedByException;
    private Object mySyncObject;

    public WebOSBuildExecutionStackCommand(boolean causedByException) {
        myTraceCommand = new WebOSGetStackTraceCommand();
        mySyncObject = new Object();
    }

    @Override
    public void execute() throws Exception {
        processStackTrace();
        ourCommandSpooler.runCommand(myTraceCommand, this);
        done();
    }

    @Override
    protected void commandFinished(BaseWebOSCommand command) throws JSONException {
        if(command == myTraceCommand) {
            myStackTrace = myTraceCommand.getStackTrace();
            ourDebugProcess.getVariableRepository().append(myTraceCommand.getVariables());
            synchronized (mySyncObject) {
                mySyncObject.notifyAll();
            }
        }
    }

    private void processStackTrace() {
        WebOSThreadHelper.run(new Runnable() {
            @Override
            public void run() {
                new Task.Backgroundable(ourDebugSession.getProject(), "Retrieving execution context", false) {
                    public void run(ProgressIndicator indicator) {
                        indicator.setIndeterminate(true);
                        synchronized (mySyncObject) {
                            try {
                                mySyncObject.wait();
                            } catch (InterruptedException e) {
                                ourDebugProcess.reportInternalError(e);
                            }
                        }
                        WebOSSuspendContext context = new WebOSSuspendContext(ourDebugProcess, myStackTrace);
                        if(!myCausedByException) {
                            WebOSExecutionStack executionStack = context.getActiveExecutionStack();
                            if (executionStack != null) {
                                WebOSStackFrame stackFrame = executionStack.getTopFrame();
                                if (stackFrame != null) {
                                    WebOSBreakpointWrapper wrapper = stackFrame.getBreakpointWrapper();
                                    if (wrapper != null) {
                                        ourDebugSession.breakpointReached(wrapper.getBreakpoint(), null, context);
                                        return;
                                    }
                                }
                            }
                        }
                        ourDebugSession.positionReached(context);
                    }
                }.queue();
            }
        });
    }    
}
